#ifndef _STOPPER_
#define _STOPPER_

#include <ctime>
#include <iostream>
#include <utility>

using namespace std;


/*
Class name:		TimeUnit      
Written by:		Oren Levi
For:			Self project
Purpose:		Objects of this class type will be used to switch between various time units.
				The program which uses this class can declare and initialize TimeUnit objects,
				change TimeUnit (using unitRef), and get TimeUnit name or value.
Member functions:	
				TimeUnit(unitRef unit =  COMPUTER_TIME)
					This c'tor function will accept from the calling program initial value
					for a time unit in the form of a timeRef.
				operator=(unitRef unit)
					This function will assign new unitRef value to an object of this class.
				name()
					This function will return the name of the time unit in the form of 
					a char* string.
				value()
					This function will return the value of the time unit in the form of
					clock_t.						
Member data:		
				_unit
					unitRef variable representing a time unit.
Static functions:	
				name(unitRef unit)
					This function will return the name of a unitRef in the form of 
					a char* string.
				value(unitRef unit)
					This function will return the value of a unitRef in the form of
					clock_t.
Static data:
				_unitNameAndValue
					pair<const char*, clock_t> constant that holds information about
					the names and values of the various time units.
*/
class TimeUnit {

public:

	typedef enum {	SECONDS = 0, MILI_SEC , COMPUTER_TIME } unitRef;

private:

	unitRef _unit;
	static const pair<const char*, clock_t> _unitNameAndValue[3];

public:

	TimeUnit(unitRef unit =  COMPUTER_TIME): _unit(unit) {};

	void operator=(unitRef unit) { _unit = unit; };

	const char* name() const { return _unitNameAndValue[_unit].first; };

	const clock_t value() const { return _unitNameAndValue[_unit].second; };

	static const char* name(unitRef unit) { return _unitNameAndValue[unit].first; };

	static const clock_t value(unitRef unit) {return _unitNameAndValue[unit].second; };

};



/*
Class name:		Stopper
Written by:		Oren Levi
For:			Self project
Purpose:		Objects of this class type will be used to count time.
				The program which uses this class can declare and initialize Stopper objects,
				reset the stopper, get and print the amount of time since the stopper was 
				initialized/reset.
Member functions:
				Stopper(TimeUnit unit = TimeUnit::COMPUTER_TIME, bool frcations = true)
					This c'tor function will start the time count. Moreover it enables the calling 
					program to set the form of ostream output (form of time unit to print 
					and whether to print in the form of fractions or integers).
				reset()
					This function will reset the time count.
				getTime(TimeUnit unit = TimeUnit::COMPUTER_TIME, bool fractions = true)
					This function will return the amount of time passed since the stopper were 
					initialized/reset. The form of the time unit and fractions/integers display
					can be chosen by the calling program.
				setOstreamFormat(TimeUnit unit, bool frcations = true)
					This function will set the form of ostream output (form of time unit to print 
					and whether to print in the form of fractions or integers).
				operator<<(ostream& out, const Stopper& st)
					This ostream function will output the amount of time passed since the stopper were 
					initialized/reset. The form of the time unit and fractions/integers display
					are preset by c'tor(initialization) or by setOstreamFormat().
Member data:
				_time0
					clock_t varuable, saves the initial/reset time.
				_unit
					TimeUnit varuable, saves the desired time unit for the ostream output.
				_fractionFlg
					bool flag, if true - the ostream output will display the time with fractions.
										
*/
class Stopper {

	clock_t _time0;
	TimeUnit _unit;
	bool _fractionFlg;

public:

	Stopper(TimeUnit unit = TimeUnit::COMPUTER_TIME, bool frcations = true): 
	  _time0(clock()), _unit(unit), _fractionFlg(frcations) {}

	void reset() { _time0 = clock(); };

	inline double getTime(TimeUnit unit = TimeUnit::COMPUTER_TIME, bool fractions = true) const;
		 
	void setOstreamFormat(TimeUnit unit, bool frcations = true) { 
		_unit = unit; 
		_fractionFlg = frcations;
	};

	friend ostream& operator<<(ostream& out, const Stopper& st) {
		out<< st.getTime(st._unit) << " " << st._unit.name();
		return out;
	};
};

#endif